package com.xm.utils.httpclient;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.http.HttpStatus;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xiumin
 * @email xiumin1993@outlook.com
 * http请求模板
 */
public class HttpTemplate {
    /**
     * 将response body转为String
     */
    public static final ResponseHandler<String> stringHandler = response -> {
        int statusCode = response.getStatusLine().getStatusCode();
        String bodyStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
        if (statusCode == HttpStatus.SC_OK) {
            return bodyStr;
        }
        throw new RuntimeException("http response error:" + statusCode + "->" + bodyStr);
    };
    /**
     * 将response body转为JSON
     */
    public static final ResponseHandler<JSONObject> jsonHandler = response -> JSON.parseObject(stringHandler.handleResponse(response));
    /**
     * header缓存，每次请求后header会被清除
     */
    private final static ThreadLocal<Map<String, String>> HEADER_CACHE = new ThreadLocal<>();

    private final CloseableHttpClient client;

    public HttpTemplate() {
        this.client = HttpClients.createDefault();
    }

    public HttpTemplate(CloseableHttpClient client) {
        this.client = client;
    }

    public void addHeader(String key, String value) {
        Map<String, String> headMap = HEADER_CACHE.get();
        if (headMap == null) {
            headMap = new HashMap<>();
            HEADER_CACHE.set(headMap);
        }
        headMap.put(key, value);
    }

    public void addHeaderBatch(Map<String, String> headers) {
        Map<String, String> headMap = HEADER_CACHE.get();
        if (headMap == null) {
            headMap = new HashMap<>();
            HEADER_CACHE.set(headMap);
        }
        headMap.putAll(headers);
    }

    public <T> T getForObject(String url, Class<T> clazz) {
        return executeForObject(new HttpGet(url), clazz);
    }

    public <T> T getForObject(String url, TypeReference<T> typeReference) {
        return executeForObject(new HttpGet(url), typeReference);
    }

    public <T> T postJsonForObject(String url, Map<String, Object> param, Class<T> clazz) {
        return executeForObject(HttpRequestUtil.newJsonPost(url, param), clazz);
    }

    public <T> T postJsonForObject(String url, Map<String, Object> param, TypeReference<T> tTypeReference) {
        return executeForObject(HttpRequestUtil.newJsonPost(url, param), tTypeReference);
    }

    public <T> T postFormUrlEncodedForObject(String url, Map<String, Object> param, Class<T> clazz) {
        return executeForObject(HttpRequestUtil.newFormUrlencodedPost(url, param), clazz);
    }

    public <T> T postFormUrlEncodedForObject(String url, Map<String, Object> param, TypeReference<T> tTypeReference) {
        return executeForObject(HttpRequestUtil.newFormUrlencodedPost(url, param), tTypeReference);
    }

    public <T> T postXmlForObject(String url, String xmlStr, Class<T> clazz) {
        return executeForObject(HttpRequestUtil.newXmlPost(url, xmlStr), clazz);
    }

    public <T> T postXmlForObject(String url, String xmlStr, TypeReference<T> tTypeReference) {
        return executeForObject(HttpRequestUtil.newXmlPost(url, xmlStr), tTypeReference);
    }

    public <T> T doGet(String url, ResponseHandler<T> handler) {
        return send(new HttpGet(url), handler);
    }

    public <T> T doPostJson(String url, Map<String, Object> param, ResponseHandler<T> handler) {
        return send(HttpRequestUtil.newJsonPost(url, param), handler);
    }

    public <T> T doPostFormUrlEncoded(String url, Map<String, Object> param, ResponseHandler<T> handler) {
        return send(HttpRequestUtil.newFormUrlencodedPost(url, param), handler);
    }

    public <T> T doPostXml(String url, String xmlStr, ResponseHandler<T> handler) {
        return send(HttpRequestUtil.newXmlPost(url, xmlStr), handler);
    }

    public <T> T send(HttpUriRequest request, ResponseHandler<T> handler) {
        try {
            Map<String, String> headerMap = HEADER_CACHE.get();
            if (null != headerMap && headerMap.size() > 0) {
                headerMap.forEach(request::addHeader);
            }
            return client.execute(request, handler);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            HEADER_CACHE.remove();
        }
    }

    /**
     * 默认返回数据为json格式，使用fastjson转换为 T
     *
     * @param request
     * @param clazz
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T executeForObject(HttpUriRequest request, Class<T> clazz) {
        String bodyStr = send(request, stringHandler);
        T body;
        if (clazz == String.class) {
            body = (T) bodyStr;
        } else if (clazz == JSONObject.class) {
            body = (T) JSON.parseObject(bodyStr);
        } else {
            body = JSON.parseObject(bodyStr, clazz);
        }
        return body;
    }

    public <T> T executeForObject(HttpUriRequest request, TypeReference<T> typeReference) {
        return send(request, jsonHandler).toJavaObject(typeReference);
    }


}
